#!/usr/bin/perl -w


### Notes:
# The -T for security check would help to protect the script but was giving error and was removed.
# The arguments been used as parameterson external commands/scripts. For the arguments only hexadecimal and - are allowed. Feel free ADD extra protectiong.
# We ignore 'format' and 'input' attributes of collector_status # Can't remember why I put this comment.

use POSIX qw(strftime);
use URI::Escape;
use Fcntl qw(:DEFAULT :flock);

use FCTranscode;


### Subroutines declarations ###


# perhaps it should return a string insted of printing
sub make_element {

                my $remote_id = shift;
                my $local_jobs_status = shift;
		my $local_col_jobs_status = shift;
		my $jobid = shift;
               print "<jobStatus ";
		print "remote_id=\"$remote_id\" ";
		print "jobid=\"$jobid\" ";
               print "batchid=\"$local_jobs_status->{$jobid}->{'batchid'}\" ";
               print "status=\"$local_jobs_status->{$jobid}->{'status'}\" ";
               print "percentComplete=\"$local_jobs_status->{$jobid}->{'percomp'}\" ";
               print "timeRemaining=\"$local_jobs_status->{$jobid}->{'timerem'}\" ";
               print "timeElapsed=\"$local_jobs_status->{$jobid}->{'timeelap'}\" ";
		print "output=\"$local_col_jobs_status->{$remote_id}->{'output'}\" ";
               print "/>\n";
}

sub make_element_col {

		my $remote_id = shift;
                my $local_jobs_status = shift;
               print "<jobStatus ";
               print "remote_id=\"$remote_id\" ";
               print "jobid=\"$local_jobs_status->{$remote_id}->{'jobid'}\" ";
               print "batchid=\"$local_jobs_status->{$remote_id}->{'batchid'}\" ";
               print "status=\"$local_jobs_status->{$remote_id}->{'status'}\" ";
               print "percentComplete=\"$local_jobs_status->{$remote_id}->{'percomp'}\" ";
               print "timeRemaining=\"$local_jobs_status->{$remote_id}->{'timerem'}\" ";
               print "timeElapsed=\"$local_jobs_status->{$remote_id}->{'timeelap'}\" ";
		print "output=\"$local_jobs_status->{$remote_id}->{'output'}\" ";
               print "/>\n";

}

### Start og main program ###

$ARGV[0] =~ s/"//g;
@subm_remote_id_list = split("&",$ARGV[0]);
#write_log($ARGV[0]);

# Reading  collector status file 
# Remember! collector uses ' instead of "

open(FH, "<", $collector_file); #TODO - Handle in case there is no collector_file
				#which would not be good since there wouldn't be request if there is no collector/is empty
flock FH, LOCK_SH;
@lines = <FH>;
flock FH, LOCK_UN;
close FH;

foreach $line (@lines) {

	$line =~ /remote_id=\'([\w\.\-]+)\'/;
	$remote_id = $1;

	#if ($line =~ /jobid=\'([[:xdigit:]-]{36})\'/){
	#	$jobid = $1; }
	#elsif ($line =~ /jobid=\'(\/[\w\/\.]+\.\d+\.status)\'/){
	#	$jobid = $1; }

	$line =~ /jobid=\'([^\']+)\'/;
	$jobid = $1;

        #if ($line =~ /batchid=\'([[:xdigit:]-]{36})\'/){
	#	$batchid = $1; }
	#elsif ($line =~ /batchid=\'(n\/a)\'/){
        #        $batchid = $1; }

	$line =~ /batchid=\'([^\']+)\'/;
	$batchid = $1;

	$line =~ /col_status=\'([\w\:\ ]+)\'/;
        $col_status = $1;

	$line =~ /transcoder=\'([\w]+)\'/;
        $transcoder = $1;

	$line =~ /status=\'([^\']+)\'/;
        $status = $1;

        $line =~ /percentComplete=\'([^\']{1,3})\'/;
        $percomp = $1;

        #$line =~ /timeRemaining=\'([\w\(\)\ \.]+)\'/;
	$line =~ /timeRemaining=\'([^\']+)\'/;
        $timerem = $1;

        #$line =~ /timeElapsed=\'([\w\(\)\']+)\'/;
	$line =~ /timeElapsed=\'([^\']+)\'/;
        $timeelap = $1;

	$line =~ /output=\'([^\']+)\'/;
	$output_file = $1;

        $collector_jobs_status{ $remote_id } = {
		jobid => $jobid,
	        batchid => $batchid,
		col_status => $col_status,
		transcoder => $transcoder,
		status => $status,
                percomp => $percomp,
                timerem => $timerem,
                timeelap => $timeelap,
		output => $output_file,
                }
}
#use Data::Dumper;
#print Dumper(%collector_jobs_status);

# Run Batch Monitor
my $cmd_str = "/Applications/Utilities/Batch\\ Monitor.app/Contents/MacOS/Batch\\ Monitor -clustername \"This Computer\"";

#print $cmd_str."\n";
$output = qx/$cmd_str/; # TODO - Check for errors
#print 'OUT:'.$output.':OUT';

open($rh, "<", \$output);

while($line = readline $rh){
	if ($line =~ /\A<jobStatus/){

		$line =~ /jobid=\"([[:xdigit:]-]{36})/;
	        $jobid = $1;

	        $line =~ /batchid=\"([[:xdigit:]-]{36})/;
		$batchid = $1;

		$line =~ /status=\"([^\"]+)\"/;
        	$status = $1;

	        $line =~ /percentComplete=\"(\d{1,3})\"/;
        	$percomp = $1;

		$line =~ /timeRemaining=\"([\w\(\)\ \.]+)\"/;
	        $timerem = $1;

	        $line =~ /timeElapsed=\"([\w\(\)\ ]+)\"/;
        	$timeelap = $1;

		$bm_jobs_status{ $jobid } = {
                		batchid => $batchid,
	                        status => $status,
        	                percomp => $percomp,
                	        timerem => $timerem,
                        	timeelap => $timeelap,
	                	};
       	}
}

#use Data::Dumper;
#print Dumper(%bm_jobs_status);

# Retrieving ffmpeg job status

# Get list of all status files
@list = glob($ffmpeg_status_files);

foreach $file (@list){
	unless ($file =~ /\A.*\..*\.\d+\.status\z/) {next;}

	# Get input video duration

	$content = `tr '\\r' '\\n' < \"$file\" | head -20`;
	unless ($content =~ /Duration: (\d{2}):(\d{2}):(\d{2})\.(\d{2})/) {
		error_die("ERROR:3013: Information extracted from status file $file is invalid."); }

	$hours = $1;
	$mins = $2;
	$secs = $3;

	$input_secs = ((($hours*60)+$mins)*60)+$secs;

	# Get transcoding start time, input and output filename

	open $ch, "<", \$content; #TODO - Handle errors
	readline $ch;
	$t_start = readline $ch;
	$out_name = readline $ch;
	$out_name =~ s/\n//g;
	close $ch;

	# Get output video (so far transcoded) duration
	
	$content = `tr '\\r' '\\n' < \"$file\" |tail -4`;
	open $ch, "<", \$content; #TODO - Handle errors
	$end1 = readline $ch;
	readline $ch;
	readline $ch;
	$end4 = readline $ch;
	close $ch;

	if ($end4 =~ /\Aframe=.+time=(\d+)\..+bitrate.+/) {
		$output_secs = $1;
		$percomp = ($output_secs/$input_secs) * 100;
		$t_current = time;
		$t_ela=$t_current-$t_start;
                $t_rem=($t_ela*(1-$percomp/100))/($percomp/100);
		$status = "Transcoding.";
	}
	elsif ($end1 =~ /\Aframe=.+time=(\d+)\..+bitrate.+/) {
		$output_secs = $1;
		$percomp = ($output_secs/$input_secs) * 100;
		if ($end4 =~ /\AFINISH: (\d+)/) {
			 $t_current = $1;
			 $t_ela = $t_current-$t_start;
			 $t_rem=($t_ela*(1-$percomp/100))/($percomp/100);
			 $status = "Completed.";
		}
		elsif ($end4 =~ /\ACANCEL: (\d+)/) {
			$t_cancel = $1;
			$t_ela = $t_cancel-$t_start;
			$t_rem=($t_ela*(1-$percomp/100))/($percomp/100);
			$status = 'Cancelled.';
		}
	}
	else { error_die("ERROR:3013: Information extracted from status file $file is invalid.");}

	
	@tEla_parts = gmtime($t_ela);
	@tRem_parts = gmtime($t_rem);
	$t_ela_str = sprintf("%d days, %02d:%02d:%02d",@tEla_parts[7,2,1,0]);
	$t_rem_str = sprintf("%d days, %02d:%02d:%02d",@tRem_parts[7,2,1,0]);

	$ffm_jobs_status{ $file } = {
        	batchid => 'n/a',
                status => $status,
                percomp => $percomp,
                timerem => $t_rem_str,
                timeelap => $t_ela_str,
                };
}


# TODO - IMPORTANT: should change them to output proper error messages

NEXT_SUBM:
foreach $subm_remote_id (@subm_remote_id_list) {

	$subm_remote_id = uri_unescape($subm_remote_id);

	#print "ITEM-----\n";
	foreach $col_key (keys %collector_jobs_status) {
		if ($subm_remote_id eq $col_key) {
			#print "Match on $col_key\n transcoder is $collector_jobs_status{$col_key}->{'transcoder'}\n";
			if ($collector_jobs_status{$col_key}->{'col_status'} eq 'waiting') {
				if ($collector_jobs_status{$col_key}->{'transcoder'} eq 'compressor'){
					$jobid = $collector_jobs_status{$col_key}->{'jobid'};
					if (exists $bm_jobs_status{$jobid}) {
						#print "KEY $col_key exists in BM\n";
						make_element($col_key, \%bm_jobs_status, \%collector_jobs_status, $jobid);
						next NEXT_SUBM;}
					else { print "jobid $jobid does not exists in BM!!!\n";
						next NEXT_SUBM;}
				}
				elsif ($collector_jobs_status{$col_key}->{'transcoder'} eq 'ffmpeg'){
					$jobid = $collector_jobs_status{$col_key}->{'jobid'};
					if (exists $ffm_jobs_status{$jobid}) {
						#print "KEY $col_key exists in FFMPEG\n";
						make_element($col_key, \%ffm_jobs_status, \%collector_jobs_status, $jobid);
						next NEXT_SUBM;}
                                        else { print "jobid $jobid does not exists in FFMPEG!!!\n";
						next NEXT_SUBM;}
				}
				else{ print "no such transcoder\n";
					next NEXT_SUBM;}
			}
			else{ make_element_col($col_key, \%collector_jobs_status);
				next NEXT_SUBM;}
		}
	}
	print "ERROR:0000: Remote id $subm_remote_id is not in collector status file $collector_file \n";
}
